﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Kokomo.Mirror.CliMetadata
{
	class StringHeapBuilder
	{
		public StringHeapBuilder(
			MetadataContainer container,
			Encoding encoding
			)
		{
			if (container == null) throw new ArgumentNullException("container");
			if (encoding == null) throw new ArgumentNullException("encoding");

			this._container = container;
			this._ecnoding = encoding;
			this._strings = new Dictionary<string, int>();
			this._stream = new MemoryStream();
			this._writer = new BinaryWriter(this._stream, encoding);

			// The initial empty string
			this._stream.WriteByte(0);
			this._strings.Add(null, 0);
			this._strings.Add(string.Empty, 0);
		}

		private Encoding _ecnoding;
		private MetadataContainer _container;
		private Dictionary<string, int> _strings;

		private MemoryStream _stream;
		private BinaryWriter _writer;

		public byte[] GetHeapData()
		{
			return this._stream.ToArray();
		}

		public void UpdateRows<TRow>(
			MetadataTable<TRow> table,
			Func<TRow, StringRef> getter,
			Action<TRow, StringRef> setter
			)
			where TRow : IMetadataRow, new()
		{
			if (table == null) throw new ArgumentNullException("table");
			if (getter == null) throw new ArgumentNullException("getter");
			if (setter == null) throw new ArgumentNullException("setter");

			MetadataContainer container = this._container;
			Dictionary<string, int> strings = this._strings;
			foreach (var row in table.Rows)
			{
				StringRef stringref = getter(row);
				string str = container.GetString(stringref);
				int index;
				if (!strings.TryGetValue(str, out index))
				{
					index = (int)this._stream.Position;
					this._writer.Write(str.ToCharArray());
					this._stream.WriteByte(0);
					strings.Add(str, index);
				}

				setter(row, new StringRef(index));
			}
		}
	}
}
